package com.bwie.auth.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.bwie.auth.pojo.bo.AsyncSendCodeBo;
import com.bwie.auth.remote.RemoteSystemService;
import com.bwie.auth.service.AuthService;
import com.bwie.common.constants.Constants;
import com.bwie.common.constants.JwtConstants;
import com.bwie.common.constants.TokenConstants;
import com.bwie.common.exceptions.BusinessException;
import com.bwie.common.pojo.req.LoginReq;
import com.bwie.common.pojo.req.SmsLoginReq;
import com.bwie.common.pojo.res.JwtRes;
import com.bwie.common.pojo.res.LoginRes;
import com.bwie.common.result.Result;
import com.bwie.common.utils.JwtUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
@Slf4j
public class AuthServiceImpl implements AuthService {
    private final RemoteSystemService remoteSystemService;
    private final RedisTemplate<String, Object> redisTemplate;
    private final RabbitTemplate rabbitTemplate;
    /**
     * 用户名密码-登录
     * @param loginReq
     * @return
     */
    @Override
    public JwtRes login(LoginReq loginReq) {
        // 根据用户名，获取用户信息
        Result<LoginRes> result = remoteSystemService.getUserByUserName(loginReq.getUserName());
        LoginRes loginRes = result.getData();

        // 判断用户名是否存在
        if (loginRes == null){
            throw new BusinessException(Constants.USER_IS_NOT_FOUND);
        }

        // 判断密码是否正确
        if (!loginReq.getPwd().equals(loginRes.getPwd())){
            throw new BusinessException(Constants.PWD_WRONG);
        }

        return getJwtRes(loginRes);
    }



    /**
     * 发送短信
     * @param phone
     */
    @Override
    public void sendCode(String phone) {
        // 验证码的key
        String sendTimeKey = Constants.SEND_TIME + phone;
        // 获取四位随机数
        int randomNumber = ThreadLocalRandom.current().nextInt(1000, 10000);

        // 转字符串
        String code = String.valueOf(randomNumber);

        AsyncSendCodeBo asyncSendCodeBo = new AsyncSendCodeBo();
        asyncSendCodeBo.setPhone(phone);
        asyncSendCodeBo.setCode(code);
        // <异步> 发送验证码
        rabbitTemplate.convertAndSend("2209a", asyncSendCodeBo);

        // 存发送时间
        redisTemplate.opsForValue().set(sendTimeKey, System.currentTimeMillis(),
                Constants.SEND_TIME_TIMEOUT_NUM, TimeUnit.MINUTES);
        // 将验证码存如redis
        redisTemplate.opsForValue().set(Constants.CODE_KEY + phone, code,
                Constants.CODE_TIMEOUT_NUM, TimeUnit.MINUTES);
        log.info("手机号：{}, 验证码：{}",phone,randomNumber);
    }

    /**
     * 手机号验证码登录
     * @param smsLoginReq
     */
    @Override
    public JwtRes smsLogin(SmsLoginReq smsLoginReq) {
        // 验证码的key
        String codeKey = Constants.CODE_KEY + smsLoginReq.getPhone();
        // 获取验证码
        String storedCode = (String) redisTemplate.opsForValue().get(codeKey);
        // 判断验证码是否已过期
        if (storedCode == null) {
            throw new BusinessException(Constants.SMS_CODE_EXPIRED);
        }
        // 判断验证码是否正确
        if (!storedCode.equals(smsLoginReq.getCode())) {
            throw new BusinessException(Constants.SMS_CODE_WRONG);
        }
        // 删除已使用的验证码
        redisTemplate.delete(codeKey);

        // 根据手机号，获取用户信息
        Result<LoginRes> result = remoteSystemService.getUserByPhone(smsLoginReq.getPhone());
        LoginRes loginRes = result.getData();

        return getJwtRes(loginRes);
    }
    
    private JwtRes getJwtRes(LoginRes loginRes) {
        // 创建一个 HashMap 对象，用于存储键值对
        HashMap<String, Object> map = new HashMap<>();
        // 生成一个唯一的 UUID 字符串
        String userKey = UuidUtils.generateUuid();
        // 存入 map
        map.put(JwtConstants.USER_KEY, userKey);
        // 生成一个 JWT 令牌，并将其赋值给 token 变量
        String token = JwtUtils.createToken(map);
        // token的key
        String loginTokenKey = TokenConstants.LOGIN_TOKEN_KEY + userKey;
        // token超时时间
        long timeoutNum = Constants.LOGIN_TOKEN_TIMEOUT_NUM;
        // 将登录响应信息以 JSON 字符串的形式存储到 Redis 中
        redisTemplate.opsForValue().set(loginTokenKey, JSON.toJSONString(loginRes), timeoutNum, TimeUnit.MINUTES);

        // 创建一个 JwtRes 对象，用于封装 JWT 相关的响应信息
        JwtRes jwtRes = new JwtRes();
        // 将生成的 JWT 令牌设置到 JwtRes 对象中
        jwtRes.setToken(token);
        // 设置失效时间
        jwtRes.setExpireTimeStr(timeoutNum + Constants.EXPIRE_TIME_UNIT);

        return jwtRes;
    }
}
